﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cmd;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
using System.Data.Common;

namespace SqlSchemaXml
{
    public class Options : OptionSet
    {
        [Option("cs", "The associated connection string.", Name = "ConnectionString")]
        [OptionGroup("ConnectionString", Required = true)]
        public string ConnectionString { get; set; }

        [Option("cn", "The associated connection name (for saved connections).", Name = "ConnectionName")]
        [OptionGroup("ConnectionName")]
        public string ConnectionName { get; set; }

        [Option("p", "The associated provider name.", Name = "Provider")]
        public string ProviderName { get; set; }

        public override bool Validate(out string[] errorMesages)
        {
            List<string> errors = new List<string>();
            string optGroup = this.GetGroup();
            switch (optGroup)
            {
                case "ConnectionString":
                    SaveConnectionString("Default", ConnectionString, ProviderName);
                    break;
                case "ConnectionName":
                    string providerName;
                    ConnectionString = GetConnectionString(ConnectionName, out providerName);
                    ProviderName = providerName;
                    break;
                default:
                    break;
            }

            if (string.IsNullOrWhiteSpace(ConnectionString))
            {
                errors.Add("Invalid connection. Please provide a valid connection string.");
            }

            if (string.IsNullOrWhiteSpace(ProviderName))
            {
                errors.Add("Invalid provider. Please provide a valid connection provider name.");
            }

            errorMesages = errors.ToArray();
            return errors.Count == 0;
        }

        public string GetConnectionString(string connectionName, out string providerName)
        {
            if (string.IsNullOrWhiteSpace(connectionName))
            {
                connectionName = "Default";
            }
            ConnectionStringSettings conn = ConfigurationManager.ConnectionStrings.OfType<ConnectionStringSettings>().FirstOrDefault(item => item.Name == connectionName);
            if (conn == null)
            {
                providerName = null;
                return null;
            }
            providerName = conn.ProviderName;
            if (string.IsNullOrWhiteSpace(providerName))
            {
                var csb = new DbConnectionStringBuilder { ConnectionString = conn.ConnectionString };
                if (csb.ContainsKey("provider"))
                {
                    providerName = csb["provider"].ToString();
                }
            }
            return conn.ConnectionString;
        }

        //private string SetupConnection(string connName, string connStr, string providerName)
        //{
        //    ConnectionStringSettings conn = null;
        //    if (!string.IsNullOrWhiteSpace(connName))
        //    {
        //        conn = ConfigurationManager.ConnectionStrings[connName];
        //    }
        //    else if (!string.IsNullOrWhiteSpace(connStr))
        //    {
        //        conn = ConfigurationManager.ConnectionStrings.OfType<ConnectionStringSettings>().FirstOrDefault(item => item.ConnectionString == connStr);
        //    }
        //    if (conn != null)
        //    {
        //        connStr = conn.ConnectionString;
        //        ProviderName = conn.ProviderName;
        //    }

        //    if (conn == null && CanConnect(connStr))
        //    {
        //        SaveConnectionString(connName, connStr, providerName);
        //    }
        //    return connStr;
        //}

        private static void SaveConnectionString(string connName, string connStr, string providerName)
        {
            System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            ConnectionStringsSection csSection = config.ConnectionStrings;

            ConnectionStringSettings css = csSection.ConnectionStrings.OfType<ConnectionStringSettings>().FirstOrDefault(item => item.ConnectionString == connStr);
            if (css != null)
            {
                csSection.ConnectionStrings.Remove(css.Name);
            }
            csSection.ConnectionStrings.Add(new ConnectionStringSettings(connName, connStr) { ProviderName = providerName });
            config.Save(ConfigurationSaveMode.Modified);
        }

        private bool CanConnect(string connectionString)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(connectionString))
                {
                    return false;
                }
                using (var connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    var canOpen = connection.State == ConnectionState.Open;
                    connection.Close();
                    return canOpen;
                }
            }
            catch
            {
                return false;
            }
        }
    }
}
